package top.codermao.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import top.codermao.stock.mapper.StockBlockRtInfoMapper;
import top.codermao.stock.mapper.StockMarketIndexInfoMapper;
import top.codermao.stock.mapper.StockRtInfoMapper;
import top.codermao.stock.pojo.domain.*;
import top.codermao.stock.pojo.vo.StockInfoConfig;
import top.codermao.stock.service.StockService;
import top.codermao.stock.utils.DateTimeUtil;
import top.codermao.stock.vo.resp.PageResult;
import top.codermao.stock.vo.resp.R;
import top.codermao.stock.vo.resp.ResponseCode;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author msk
 * @date 2024/4/17 20:52
 * @Description 股票服务接口
 */
@Service
@Slf4j
public class StockServiceImpl implements StockService {
    @Autowired
    private StockInfoConfig stockInfoConfig;
    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;
    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    /**
     * 获取国内大盘最新的数据
     *
     * @return
     */
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfo() {
        //1.获取股票最新交易时间点，精确到分钟，秒和毫秒置为0
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock data 等后续完成job工程，再将代码删除即可
        curTime = DateTime.parse("2022-07-07 14:52:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取大盘编码集合
        List<String> mCodes = stockInfoConfig.getInner();
        //3.调用mapper查询数据
        List<InnerMarketDomain> data = stockMarketIndexInfoMapper.getInnerMarketInfo(curTime, mCodes);
        //4.封装并相应
        return R.ok(data);
    }

    /**
     * 需求说明: 获取沪深两市板块最新数据，以交易总金额降序查询，取前10条数据
     *
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> sectorAllLimit() {
        //获取最近的有效交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock date
        curTime = DateTime.parse("2022-01-14 16:57:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //
        List<StockBlockDomain> data = stockBlockRtInfoMapper.sectorAllLimit(curTime);
        //2.组装数据
        if (CollectionUtils.isEmpty(data)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(data);
    }

    /**
     * 分页查询最新的股票交易数据
     *
     * @param page     当前页
     * @param pageSize 每页大小
     * @return
     */
    @Override
    public R<PageResult<StockUpdownDomain>> getStockInfoByPage(Integer page, Integer pageSize) {
        //获取最近的有效交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock date
        curTime = DateTime.parse("2022-07-07 14:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //设置pageHelper分页参数
        PageHelper.startPage(page, pageSize);
        List<StockUpdownDomain> pageData = stockRtInfoMapper.getStockInfoByTime(curTime);
        if (CollectionUtils.isEmpty(pageData)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }
        //获取组装pageResult对象
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(pageData);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        //响应数据
        return R.ok(pageResult);
    }

    /**
     * 查询部分最新的股票交易数据
     *
     * @return
     */
    @Override
    public R<List<StockUpdownDomain>> getStockInfoSegment() {
        //获取最近的有效交易时间点
        Date curTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock date
        curTime = DateTime.parse("2022-07-07 14:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.掉用mapper查询
        List<StockUpdownDomain> infos = stockRtInfoMapper.getStockInfoSegment(curTime);

        //3.返回数据
        return R.ok(infos);
    }

    /**
     * 统计最新股票交易日内每分钟的涨跌停的股票数量
     * @return
     */
    @Override
    public R<Map<String, List>> getStockUpDownCount() {
        //获取最新股票交易时间点（截止时间）
        //获取最近的有效交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //mock date
        curDateTime = DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = curDateTime.toDate();
        //获取最新交易时间点对应的开盘时间
        Date startDate = DateTimeUtil.getOpenDate(curDateTime).toDate();
        //3.统计涨停
        List<Map> upList = stockRtInfoMapper.getStockUpdownCount(startDate,endDate,1);
        //4.统计跌停
        List<Map> downList = stockRtInfoMapper.getStockUpdownCount(startDate,endDate,0);
        //组装数据
        HashMap<String, List> info = new HashMap<>();
        info.put("upList",upList);
        info.put("downList",downList);
        //响应数据
        return R.ok(info);
    }

    /**
     * 导出指定页码的股票信息
     * @param page  当前页
     * @param pageSize 每页大小
     * @param response
     */
    @Override
    public void exportStockUpDownInfo(Integer page, Integer pageSize, HttpServletResponse response) {
        //获取分页数据
        R<PageResult<StockUpdownDomain>> r = this.getStockInfoByPage(page, pageSize);
        List<StockUpdownDomain> rows = r.getData().getRows();
        //将数据导出到excel中
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        try {
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("股票信息表", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class).sheet("股票涨幅信息").doWrite(rows);
        } catch (IOException e) {
            log.error("当前页码：{}，每页大小：{}，时间：{}",page,pageSize,DateTime.now().toString("yyyy-MM-dd HH:mm:ss"),e.getMessage());
            //通知前端异常，稍后重试
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            R<Object> error = R.error(ResponseCode.ERROR);
            try {
                String jsonData = new ObjectMapper().writeValueAsString(error);
                response.getWriter().write(jsonData);
            } catch (IOException ex) {
                log.error("exportStockUpDownInfo响应错误信息失败，时间：{}",DateTime.now().toString("yyyy-MM-dd HH:mm:ss"),e.getMessage());
            }
        }
    }

    /**
     * 统计大盘T日和T-1日每分钟交易量的统计
     * @return
     */
    @Override
    public R<Map<String, List>> getComparedStockTradeAmt() {
        //获取T日（最新股票交易日的日期范围）
        DateTime tEndDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //mock data
        tEndDateTime =DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date tEndDate = tEndDateTime.toDate();
        //开盘时间
        Date tStartDate = DateTimeUtil.getOpenDate(tEndDateTime).toDate();
        //获取T-1日的时间范围
        DateTime preTEndDateTime = DateTimeUtil.getPreviousTradingDay(tEndDateTime);
        //mock data
        preTEndDateTime = DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date preTEndDate = preTEndDateTime.toDate();
        //开盘时间
        Date preStartDate = DateTimeUtil.getOpenDate(preTEndDateTime).toDate();
        //调用mapper查询
        //统计T日
        List<Map> tData = stockMarketIndexInfoMapper.getSumAmtInfo(tStartDate, tEndDate, stockInfoConfig.getInner());
        //统计T日
        List<Map> preTData = stockMarketIndexInfoMapper.getSumAmtInfo(preStartDate, preTEndDate, stockInfoConfig.getInner());
        //组装数据
        HashMap<String, List> info = new HashMap<>();
        info.put("amtList",tData);
        info.put("yesAmtList",preTData);
        //响应数据
        return R.ok(info);
    }

    /**
     * 统计最新交易时间点下，股票在各个涨幅区间的数量
     * @return
     */
    @Override
    public R<Map> getIncreaseRangeInfo() {
        //1.获取当前股票最新交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //mock data
        curDateTime =DateTime.parse("2022-01-06 09:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date curDate = curDateTime.toDate();
        //2.调用mapper获取数据
        List<Map> infos = stockRtInfoMapper.getIncreaseRangeInfoByDate(curDate);
        //获取有序的涨幅区间标题集合
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        //将顺序的涨幅区间内的每个元素转换成Map对象
        /*List<Map> allInfos = new ArrayList<>();
        for (String title : upDownRange) {
            Map tmp = null;
            for (Map info : infos) {
                if (info.containsValue(title)) {
                    tmp = info;
                    break;
                }
            }
            if (tmp == null) {
                //不存在则补齐
                tmp = new HashMap();
                tmp.put("count",0);
                tmp.put("title",title);
            }
            allInfos.add(tmp);
        }*/
        List<Map> allInfos = upDownRange.stream().map(title->{
            Optional<Map> result = infos.stream().filter(map->map.containsValue(title)).findFirst();
            if (result.isPresent()) {
                return result.get();
            }else{
                HashMap<String, Object> tmp = new HashMap<>();
                tmp.put("count",0);
                tmp.put("title",title);
                return tmp;
            }
        }).collect(Collectors.toList());

        //3.组装数据
        HashMap<String, Object> data = new HashMap<>();
        data.put("time",curDateTime.toString("yyyy-MM-dd HH:mm:ss"));
        data.put("infos",allInfos);
        //4.响应
        return R.ok(data);
    }

    /**
     * 获取指定股票T日分时数据
     * @param stockCode
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStockScreenTimeSharing(String stockCode) {
        //1.获取T日最新股票交易时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endDate = endDateTime.toDate();

        //mock data
        endDateTime = DateTime.parse("2021-12-30 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        endDate = endDateTime.toDate();

        Date openDate = DateTimeUtil.getOpenDate(endDateTime).toDate();
        //2.查询
        List<Stock4MinuteDomain> data = stockRtInfoMapper.getStock4MinuteInfo(openDate,endDate,stockCode);
        //3.返回
        return R.ok(data);
    }

    /**
     * 查询指定股票的日k线数据
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Stock4EvrDayDomain>> getStockScreenDkLine(String stockCode) {
        //1.获取统计的日K线数据，时间范围
        //1.1获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());

        endDateTime = DateTime.parse("2022-06-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));

        Date endDate = endDateTime.toDate();
        //1.2获取起始时间
        DateTime startDateTime = endDateTime.minusMonths(3);

        startDateTime = DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));

        Date startDate = startDateTime.toDate();

        //2.调用mapper获取指定日期范围内的日k线数据
        List<Stock4EvrDayDomain> dkLineData = stockRtInfoMapper.getStock4DkLine(startDate,endDate,stockCode);
        //3.返回
        return R.ok(dkLineData);
    }
}
